/*
 * Class AI
 * 
 * The implemented AI class plays the role of the opposing player.
 */

/**
 *
 * @author Jill Greczek, Julio Montero, Brandon Jarratt
 */

/**
 * GLOBAL: Possible difficulty settings (EASY, MEDIUM, or HARD).
 */
enum Difficulty {EASY, MEDIUM, HARD};

/**
 * GLOBAL: Possible player colors (BLACK, WHITE, or EMPTY).
 */
enum Player {BLACK, WHITE, EMPTY};

public class team2_AI
{
	/** The decision tree that is used to choose the best next move. */
	public MinimaxTree minimax;
	
    /**
     * The index of the row index in a length 2 integer array specifying
     * a move.
     */
    public static final int ROW_INDEX = 0;
    /**
     * The index of the column index in a length 2 integer array specifying
     * a move.
     */
    public static final int COL_INDEX = 1;

    /** The player color. */
    private Player player;

    /** The AI's difficulty level. */
    private Difficulty difficulty;

    /** The current state of the board. */
    Player[][] boardState;
    
    /** The previous state of the board. */
    Player[][] prevState;

    /** The last move that was made. */
    public int[] lastMove;

    /**
     * Constructs an AI object with a specified difficulty level.
     * @param difficult a difficulty level (EASY, MEDIUM, or HARD)
     * @throws IllegalArgumentException if the <code>player</code> argument is <code>Player.EMPTY</code>
     */
    public team2_AI(Player player, Difficulty difficulty) throws IllegalArgumentException
    {
        if(player == Player.EMPTY){
            throw new IllegalArgumentException("Constructing an AI player for Othello requires either a BLACK or WHITE player.");
        }
        this.player = player;
        this.difficulty = difficulty;
        
        //initialize board state to new game
        boardState = new Player[8][8];
        for(int i = 0; i < boardState.length; i++)
			for(int j = 0; j < boardState[i].length; j++)
				boardState[i][j] = Player.EMPTY;
        boardState[3][3] = Player.WHITE;
        boardState[4][3] = Player.BLACK;
        boardState[4][4] = Player.WHITE;
        boardState[3][4] = Player.BLACK;
        
        //determine depth of tree via difficulty level
        int depth = 0;
        if(difficulty.equals(Difficulty.EASY))
        {
        	depth = 2;
        }
        else if(difficulty.equals(Difficulty.MEDIUM))
        {
        	depth = 4;
        }
        else{
        	depth = 6;
        }
        
        //initialize the minimax tree to the starting formation
        minimax = new MinimaxTree(boardState, depth, new MinimaxNode(), player);
    }

    /**
     * Returns the difficulty level of this AI player.
     */
    public final Difficulty getDifficulty()
    {
        return difficulty;
    }

    /**
     * Returns the player color (BLACK or WHITE).
     */
    public final Player getPlayer()
    {
        return player;
    }
    
    /** Returns the board state. */
    public Player[][] getBoardState()
    {
    	return boardState;
    }

    /**
     * Returns the desired move in the length 2 integer array making the
     * decision based on the <code>boardState</code>, an 8x8 array of
     * <code>Player</code> objects (BLACK, WHITE, or EMPTY), the
     * <code>lastMove</code>, a length 2 integer array, and any other
     * stored information. The desired move is specified by two indices the
     * first index (e.g. <code>lastMove[ROW_INDEX]</code>) refers to a row of
     * the game board and the second index
     * (e.g. <code>lastMove[COL_INDEX]</code>) refers to a column of the game
     * board.<p></p>
     *
     * Any invalid moves should be interpreted as a pass. Changes to the
     * <code>boardState</code> parameter are permitted.
     *
     * @param boardState a two dimensional 8x8 array representing the state of
     * an Othello game board
     * @param lastMove the move made by the last player
     * @return a desired move, which is a length 2 integer array specifying a
     * row and column to place a piece
     */
    public int[] makeMove(Player[][] boardState, int[] lastMove)
    {
    	if(minimax.getNextMove()[0] == -1 || minimax.getNextMove()[1] == -1){
    		int[] bad = new int[2];
    		bad[0] = -1;
    		bad[1] = -1;
    		return bad;
    	}
    	int[] nextMove = minimax.getNextMove();

    	//update board state based on this move
    	prevState = minimax.copy(boardState);
    	updateBoardState(minimax.getModifiedState(minimax.copy(boardState), player, nextMove));
    	
    	//update the 'last move' variable
    	updateLastMove(nextMove);
    	
    	//update the minimax tree - this is very important!
    	//the minimax tree must be updated with a new root once it is our turn again
    	
    	return nextMove;
    }

    /** Updates board state. */
    public void updateBoardState(Player[][] newState) {boardState = newState;}

    /** Updates last move made. */
    public void updateLastMove(int[] newLastMove) {lastMove = newLastMove;}
    
    /** !!!  Updates the minimax tree AFTER the other player takes their turn. !!! */
    public void updateMinimax(int[] opponentMove, Player opponentColor)
    {
    	//update board state after opponent move
    	prevState = minimax.copy(boardState);
    	updateBoardState(minimax.getModifiedState(minimax.copy(boardState), opponentColor, opponentMove));
    	
    	//calculate depth again
    	int depth = 0;
        if(difficulty.equals(Difficulty.EASY))
        {
        	depth = 2;
        }
        else if(difficulty.equals(Difficulty.MEDIUM))
        {
        	depth = 4;
        }
        else{
        	depth = 6;
        }
        
        //update minimax tree using the current board state
    	minimax = new MinimaxTree(boardState, depth, new MinimaxNode(), player);
    }
    
    public void adjust(int mymove, int opponentmove){
    	//nothing - defined in LearningAI
    }

}
